<template>
  <div>
    <n-scrollbar style="max-height: 1000px">
      <n-el>
        <n-row
            style="-webkit-app-region: drag;position:fixed;top:0px;z-index: 3999;background-color: var(--body-color);color: var(--primary-color);transition: 0.3s var(--cubic-bezier-ease-in-out);">
          <n-col span="12">
            <n-space justify="start" size="small">
              <svg t="1669713407659" style="height:15px;width:15px;padding: 10px 0 0 10px;fill:var(--icon-color)"
                   class="icon"
                   viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1492" width="256"
                   height="256">
                <path
                    d="M648.37 512l305-396.49A32 32 0 0 0 928 64H639.51a96.6 96.6 0 0 0-76.09 37.47l-48 62.45L459.6 98a95.83 95.83 0 0 0-73.28-34H96a32 32 0 0 0-24.43 52.67L406.08 512 71.57 907.33A32 32 0 0 0 96 960h290.32a95.83 95.83 0 0 0 73.28-34l55.79-65.93 48 62.45A96.6 96.6 0 0 0 639.51 960H928a32 32 0 0 0 25.36-51.51z m-262-384a32 32 0 0 1 24.43 11.33l64.71 76.48L439.19 263 325 128z m-145.16 0L416 334.57a32 32 0 0 0 49.81-1.17l75.91-98.68 0.26-0.35 72.22-93.88A32.21 32.21 0 0 1 639.51 128H703L446.81 461.06 165 128z m0 768H165l307.11-363 0.18-0.2 0.09-0.1 0.09-0.12c0.3-0.36 0.6-0.72 0.88-1.08l0.05-0.07L783.76 128H863L583.09 491.9z m398.35 0a32.21 32.21 0 0 1-25.36-12.49l-56.52-73.41 41.51-49.1L703 896z m144.25 0l-158-205.41a32.52 32.52 0 0 0-4.7-4.92 32 32 0 0 0-45.1 3.76l-83.51 98.69-0.33 0.39-81.36 96.16A32 32 0 0 1 386.32 896H325l281.81-333.06L863 896z"
                    fill="#5C5C66" p-id="1493"></path>
              </svg>


              <!--          <n-image width="15" style="padding: 5px 0 0 5px;"-->
              <!--                   src=""></n-image>-->
              <n-gradient-text
                  style="padding: 6px 0 0 0px;-moz-user-select: none;-khtml-user-select: none;user-select: none;"
                  :gradient="{deg: 180,from: 'rgb(85, 85, 85)',to: 'rgb(170, 170, 170)'}">
                mkv-batch-remux
              </n-gradient-text>
            </n-space>
          </n-col>
          <n-col span="12">
            <n-space justify="end" size="small">
              <n-button quaternary style="font-size: 20px;padding: 2px 0 0 0;-webkit-app-region: no-drag"
                        @click="minimize">
                <n-icon>
                  <remove/>
                </n-icon>
              </n-button>
              <n-button quaternary style="font-size: 16px;padding: 1px 0 0 0;-webkit-app-region: no-drag"
                        @click="maximize">
                <n-icon>
                  <stop-outline/>
                </n-icon>
              </n-button>
              <n-button quaternary style="font-size: 20px;padding: 5px;-webkit-app-region: no-drag" @click="closeApp">
                <n-icon>
                  <close/>
                </n-icon>
              </n-button>
            </n-space>
          </n-col>
        </n-row>
      </n-el>

      <n-el>
        <n-row>
          <n-col>&nbsp;</n-col>
        </n-row>
        <n-row v-if="showFirstRow">
          <n-col>&nbsp;</n-col>
        </n-row>
        <n-row>
          <n-col span="1"></n-col>
          <n-col span="22">
            <n-alert v-if="showFirstRow" title="说明" type="info" closable :on-close="closeInfo">
              这是一个好东西
            </n-alert>
          </n-col>
          <n-col span="1"></n-col>
        </n-row>
        <n-row>
          <n-col>&nbsp;</n-col>
        </n-row>
        <n-row>
          <n-col span="1"></n-col>
          <n-col span="22">
            <n-card hoverable>
              <n-input-group>
                <n-input-group-label @dblclick="openDevTools">MKVToolNix</n-input-group-label>
                <n-input v-model:value="mkvtoolnix" :style="{ width: '100%' }"/>
                <n-button @click="selectMkvtoolnix" type="default" ghost>
                  <template #icon>
                    <n-icon>
                      <settings/>
                    </n-icon>
                  </template>
                  设置
                </n-button>
                <n-button @click="light" type="default" ghost icon-placement="right">
                  <template #icon>
                    <n-icon>
                      <contrast/>
                    </n-icon>
                  </template>
                  {{ props.theme?.name === 'dark' ? '开灯' : '关灯' }}
                </n-button>
              </n-input-group>
            </n-card>
          </n-col>
          <n-col span="1"></n-col>
          <!--      <Col span="4">-->
          <!--        <Button @click="selectMkvtoolnix" type="primary"  long>选择mkvtoolnix</Button>-->
          <!--      </Col>-->
        </n-row>
        <n-row>
          <n-col>&nbsp;</n-col>
        </n-row>
        <n-row>
          <n-col span="1"></n-col>
          <n-col span="22">
            <n-card hoverable>
              <n-spin :stroke-width="30" :description="str" size="large" :show="spinShow">
                <n-upload
                    ref="upload"
                    multiple
                    directory
                    :on-before-upload="beforeUpload"
                    @click="spinShow=true"
                    directory-dnd
                    accept=".mkv, .fixed"
                    action="https://www.mocky.io/v2/5e4bafc63100007100d8b70f"
                >
                  <n-upload-dragger>
                    <div style="margin-bottom: 12px">
                      <n-icon size="48" :depth="3">
                        <archive-outline/>
                      </n-icon>
                    </div>
                    <n-text style="font-size: 16px">
                      点击或者拖动文件到该区域来上传
                    </n-text>
                    <n-p depth="3" style="margin: 8px 0 0 0">
                    </n-p>
                  </n-upload-dragger>
                </n-upload>
              </n-spin>
              <template #footer>
                <n-space justify="end">
                  <!--            <n-checkbox v-model:checked="ignoreSubtitle">忽略字幕</n-checkbox>-->
                  <n-popover trigger="hover">
                    <template #trigger>
                      <n-checkbox v-model:checked="readNfo">
                        <n-icon style="top:2px">
                          <information-circle/>
                        </n-icon>
                        读取nfo信息
                      </n-checkbox>
                    </template>
                    <span>读取影片的中文名称</span>
                  </n-popover>
                  <n-checkbox v-model:checked="ignoreFixed">
                    <n-icon style="top:2px">
                      <construct-outline/>
                    </n-icon>
                    忽略已处理
                  </n-checkbox>
                  <n-popover trigger="hover">
                    <template #trigger>
                      <n-checkbox v-model:checked="readMediainfoXml">
                        <n-icon style="top:2px">
                          <reader/>
                        </n-icon>
                        读取mediainfo.xml
                      </n-checkbox>
                    </template>
                    <span>会缺少轨道的大小数据</span>
                  </n-popover>
                  <!--                <n-checkbox v-model:checked="noCheckSingleAudio">单音轨不选</n-checkbox>-->
                </n-space>
              </template>
            </n-card>
          </n-col>
          <n-col span="1"></n-col>
        </n-row>
        <n-row>
          <n-col>
            <!--        <Button @click="show" size="small" icon="md-trash">看看</Button>-->
            &nbsp;
          </n-col>
        </n-row>
        <n-row>
          <n-col span="1"></n-col>
          <n-col span="22">
            <n-card hoverable>
              <template #header>
                <n-space>
                  <n-icon style="top:3px">
                    <film-outline/>
                  </n-icon>

                  <span>{{ `所有文件 : ${data.length} 个` }}</span>
                  <span>{{ `选中文件 : ${checkedAndIndeterminateKeys.length} 个` }}</span>
                </n-space>
              </template>
              <template #header-extra>
                <!--                <n-affix :trigger-top="50">-->
                <n-space justify="end">

                  <!--                  <div style="width: 160px">-->
                  <!--                    {{ str }}-->
                  <!--                  </div>-->
                  <!--                <Switch v-model="subtitleSwitch" size="small">-->
                  <!--                  <template #open>字</template>-->
                  <!--                  <template #close>字</template>-->
                  <!--                </Switch>-->
                  <n-badge dot :show="false">
                    <n-button @click="clear" :disabled="!miFinished" size="tiny">
                      <template #icon>
                        <n-icon>
                          <trash/>
                        </n-icon>
                      </template>
                      清空
                    </n-button>
                  </n-badge>
                  <n-badge dot :show="!!mkvmegerProcess" :processing="loading">
                    <n-button @click="openLog" size="tiny">
                      <template #icon>
                        <n-icon>
                          <reader/>
                        </n-icon>
                      </template>
                      日志
                    </n-button>
                  </n-badge>
                  <!--                <Poptip v-if="!miFinished" trigger="focus" title="提示" word-wrap-->
                  <!--                        content="导入文件后请先分析出轨道数据">-->
                  <!--                  <Button ref="fxbutton" @click="startMediaInfo" size="small" icon="md-cog">分析</Button>-->
                  <!--                </Poptip>-->
                  <n-badge dot :show="false">
                    <n-button @click="start" :disabled="!miFinished" :loading="loading" size="tiny">
                      <template #icon>
                        <n-icon>
                          <construct/>
                        </n-icon>
                      </template>
                      处理
                    </n-button>
                  </n-badge>
                </n-space>
                <!--                </n-affix>-->
              </template>
              <n-row>
                <n-col :span="18">
                  <n-space>
                    <n-dropdown size="small" trigger="hover"
                                :options="[{key:'all',label:'全选'},
                            {key:'none',label:'全不选'},
                            {key:'unDeal',label:'全选未处理'},
                            {key:'unDealButSingleAudio',label:'全选未处理-除单音轨外'},
                            {key:'smart',label:'智能选择'}]"
                                @select="handleSelect"
                                placement="bottom-end">
                      <n-button text size="tiny" icon-placement="right">
                        <template #icon>
                          <n-icon>
                            <chevron-down/>
                          </n-icon>
                        </template>
                        选择
                      </n-button>
                    </n-dropdown>
                    <n-switch size="small" :default-value="true" :on-update:value="changeShowSubtitle">
                      <template #checked>
                        显示字幕
                      </template>
                      <template #unchecked>
                        隐藏字幕
                      </template>
                      <template #checked-icon>
                        <n-icon :component="Text">
                        </n-icon>
                      </template>
                      <template #unchecked-icon>
                        <n-icon>
                          <text-outline/>
                        </n-icon>
                      </template>
                    </n-switch>
                    <span v-if="lose">
                  预计总瘦身 : {{ transSize(lose) }}
                </span>
                    <span v-if="alreadyLose">
                  已经总瘦身 :{{ transSize(alreadyLose) }}
                </span>
                  </n-space>
                </n-col>
                <n-col :span="6">
                  <n-space justify="end">
                    <n-button-group>
                      <n-button round @click="up" size="tiny">
                        <template #icon>
                          <n-icon>
                            <arrow-up/>
                          </n-icon>
                        </template>
                      </n-button>
                      <n-button round @click="down" size="tiny">
                        <template #icon>
                          <n-icon>
                            <arrow-down/>
                          </n-icon>
                        </template>
                      </n-button>
                    </n-button-group>
                  </n-space>
                </n-col>
              </n-row>
              <n-divider/>
              <n-tree
                  ref="tree"
                  style="height: 800px;user-select:text"
                  block-line
                  block-node
                  cascade
                  :data="data"
                  v-model:expanded-keys="expandedKeys"
                  v-model:checked-keys="checkedKeys"
                  v-model:indeterminate-keys="indeterminateKeys"
                  v-model:selected-keys="selectedKeys"
                  :render-label="renderLabel"
                  checkable
                  selectable
                  label-field="title"
                  :show-irrelevant-nodes="showIrrelevantNodes"
                  :pattern="pattern"
                  :filter="filterNode"
                  :virtual-scroll="treeVirtualScroll"

              >
                <template #empty>
                  <n-empty description="暂无数据">
                    <template #extra>
                    </template>
                  </n-empty>
                </template>
              </n-tree>

              <!--          <Tree :data="data" show-checkbox></Tree>-->
            </n-card>
          </n-col>
          <n-col span="1"></n-col>
        </n-row>
        <n-row>
          <n-col>&nbsp;</n-col>
        </n-row>
        <n-drawer :height="410" display-directive="show" placement="bottom" :on-after-enter="scrollLog"
                  v-model:show="drawerOpen">
          <n-drawer-content title="处理日志">
            <template #header>
              <n-space>
                <span>处理日志</span>
                <span v-show="loading" style="width: 50%">
                  <n-progress
                      type="line"
                      :percentage="finishPercent"
                      :indicator-placement="'inside'"
                      processing
                  >
                   {{ finishCount }} / {{ allCount }}
                  </n-progress>
                </span>
              </n-space>
            </template>
            <n-log style="user-select:text" :ref="setRefs" :log="mkvmegerProcess" trim>
            </n-log>
            <!--        <div id="logDiv" style="white-space: pre-wrap">{{ mkvmegerProcess }}</div>-->
            <!--        <n-scrollbar :ref="setRefs" trigger="none" style="height: 100%">{{ mkvmegerProcess }}</n-scrollbar>-->
            <template #footer>
              <n-button @click="clearLog" size="tiny" icon="md-trash">
                <template #icon>
                  <n-icon>
                    <trash/>
                  </n-icon>
                </template>
              </n-button>
            </template>
          </n-drawer-content>
        </n-drawer>
      </n-el>
    </n-scrollbar>
  </div>
</template>

<script setup lang="jsx">
import {computed, nextTick, onMounted, reactive, ref, watch} from 'vue'
import {
  ArchiveOutline,
  ArrowDown,
  ArrowUp,
  ChevronDown,
  Close,
  Construct,
  ConstructOutline,
  Contrast,
  Document,
  Film,
  FilmOutline,
  InformationCircle,
  MusicalNotes,
  Reader,
  Remove,
  Settings,
  StopOutline,
  Text,
  TextOutline,
  Trash
} from "@vicons/ionicons5";
import {useMessage, useNotification} from 'naive-ui'
import {sum} from "lodash-es"

const props = defineProps(['theme'])
const treeVirtualScroll = ref(process.env.NODE_ENV !== 'development')
const showFirstRow = ref(false)
const pattern = ref('')
const showIrrelevantNodes = ref(true)
const subtitleSwitch = ref(true)
const ignoreSubtitle = ref(false)
const ignoreFixed = ref(false)
const readMediainfoXml = ref(false)
const noCheckSingleAudio = ref(false)
const upload = ref()
const loading = ref(false)
const mkvtoolnix = ref()
const mkvmegerProcess = ref('')
const spinShow = ref(false)
const miFinished = ref(false)
const mediainfoFiles = ref([])
const checkedKeys = ref([])
const indeterminateKeys = ref([])
const expandedKeys = ref([])
const current = ref(0)
const drawerOpen = ref(false)
const fixedFiles = ref([])
const nfoFiles = ref([])
const data = ref([])
const emit = defineEmits(['light'])
const lose = computed(() => {
  return sum(data.value?.filter(d => indeterminateKeys.value?.includes(d.key)).map(d =>
      sum(d.children?.filter(c => !checkedKeys.value?.includes(c.key) && c.size).map(c => parseInt(c.size)))
  ))
})
const alreadyLose = computed(() => {
  return sum(data.value.filter(d => d.oldSize).map(d => parseInt(d.oldSize) - parseInt(d.size)))
})
const str = computed(() => {
  let s
  if (spinShow.value && mediainfoFiles.value?.length) {
    s = `正在分析 ${current.value + 1} / ${mediainfoFiles.value.length}`
  } else {
    s = ''
  }
  return s
})
const openLog = e => {
  drawerOpen.value = true

}
const openDevTools = () => {
  window.electronAPI.openDevTools()
}

const light = (e) => {
  emit('light')

}
const closeInfo = () => {
  showFirstRow.value = false
  return true
}
let MediaInfoModule
const checkTree = () => {
  console.log(data)
}
const beforeUpload = (file) => {
  return false
}
const filterNode = (pattern, node) => {
  return node.type !== 't'
}
const changeShowSubtitle = (v) => {
  if (v) {
    pattern.value = ''
    showIrrelevantNodes.value = true
  } else {
    pattern.value = 't'
    showIrrelevantNodes.value = false
  }
}
const readNfo = ref(true)
const handleSelect = (key) => {

  if (key === 'all') {
    checkedKeys.value = data.value.map(d => d.key)
  }
  if (key === 'none') {
    checkedKeys.value = []
    indeterminateKeys.value = []
  }
  if (key === 'unDeal') {
    checkedKeys.value = data.value.filter(d => !d.fixed).map(d => d.key)
  }
  if (key === 'unDealButSingleAudio') {
    checkedKeys.value = data.value.filter(d => !d.fixed && !d.singleAudio).map(d => d.key)
  }
  if (key === 'smart') {
    /**
     * 1.单音轨不选
     * 2.只有中文音轨不选
     * 3.全是原语言音轨不选
     * 4.全是原语言与中文音轨不选
     * 5.只选择原语言及中文音轨与字幕
     */
    let ika = []
    let cka = []
    data.value.forEach(d => {
      if (!d.fixed && !d.singleAudio && d.hasOtherLanguageAudio) {


        d.children.forEach(c => {
          if (c.type === 'v') {
            ika.push(d.key)
            cka.push(c.key)
          }
          if ((c.type === 'a' || c.type === 't') && (d.language === c.language || c.language === 'Chinese')) {
            ika.push(d.key)
            cka.push(c.key)
          }
        })
      }
    })
    indeterminateKeys.value = ika
    checkedKeys.value = cka
  }

}

// const onUpdateChecked = (newValue, oldValue) => {
//   lose.value = 0
//   for (let i = 0; i < data.value.length; i++) {
//     const d = data.value[i]
//     if (newValue.includes(d.key) || indeterminateKeys.value.includes(d.key)) {
//       for (let j = 0; j < d.children.length; j++) {
//         const c = d.children[j]
//         if (!newValue.includes(c.key)) {
//           const size = c.size
//           if (size) {
//             lose.value += parseInt(size)
//           }
//         }
//       }
//     }
//   }
// }
// watch(checkedKeys, onUpdateChecked)
const tooltipsRef = []
const renderLabel = ({option, checked, selected}) => {
  let icon = Document
  if (option.type === 'v') {
    icon = Film
  } else if (option.type === 'a') {
    icon = MusicalNotes
  } else if (option.type === 't') {
    icon = Text
  }

  const refTooltip = tooltip => {
    if (tooltip) {
      tooltip.trackKey = option.key
      tooltipsRef.push(tooltip)
    }
  }
  let titleText = ` ${option.title}`
  const titleStyle = {}
  if (option.fixed) {
    if (!option.type) {
      titleText += ` (已处理,瘦身 ${transSize(option.oldSize - option.size)})`
    }
    titleStyle.color = 'var(--info-color)'
  }
  if (option.tName) {
    let prefixTitle = option.tName
    if (option.language) {
      prefixTitle += ` | ${option.language}`
    }
    titleText = ` ${prefixTitle} |${titleText}`
  }
  const titleVNode = <span style={titleStyle}>{titleText}</span>
  return <n-popover trigger="click" scrollable
                    style="max-height: 500px;width: 600px;white-space: pre-wrap;user-select:text">
    {{
      trigger: () =>
          <n-tooltip ref={refTooltip} display-directive="show" trigger="manual">
            {{
              trigger: () => <div style="user-select:text;" id={`d_${option.key}`}>
                <n-el>
                  <n-icon style="top:2px" component={icon}/>
                  {titleVNode}
                </n-el>
              </div>,
              default: () => '请至少选择一条'
            }}
          </n-tooltip>,
      header: () => option.titleGeneral ? option.titleGeneral + ' | ' + option.title : option.title,
      default: () => option.path ? `File Path : ${option.path} \n ${option.inform} ` : option.inform
    }}

  </n-popover>
}
const message = useMessage()
const tree = ref()
const shake = key => {
  const child = document.getElementById(`d_${key}`);
  if (child) {
    child.className = 'shake'
    setTimeout(() => {
      child.className = ''
    }, 3000)
  } else {
    console.error(key)
  }

}

const start = (e) => {
  if (data.value.length) {
    data.value.forEach(d => {
      d.checked = false
      if (d.children && d.children.length) {
        d.children.forEach(c => {
          c.checked = false
        })
      }
    })


    data.value.forEach(d => {
      if (checkedKeys.value.includes(d.key)) {
        d.checked = true
        d.children.forEach(c => {
          c.checked = true
        })
      } else if (d.children && d.children.length) {
        d.children.forEach(c => {
          if (checkedKeys.value.includes(c.key)) {
            c.checked = true
            d.checked = true
          }
        })
      }
    })

    const showTooltipAndShake = (file, type) => {

      tree.value?.scrollTo({key: file.key})
      setTimeout(() => {
        for (let j = 0; j < tooltipsRef.length; j++) {
          const tooltip = tooltipsRef[j]
          if (tooltip.trackKey === file.key) {
            if (tooltip.popoverRef) {
              tooltip.syncPosition()
              nextTick(() => {
                tooltip.setShow(true)
                setTimeout(() => {
                  tooltip.setShow(false)
                }, 2000)
                for (let i = 0; i < file.children.length; i++) {
                  const c = file.children[i]
                  if (type === c.type) {
                    shake(c.key)
                  }
                }
              })
            }
          }
        }
      }, 500)
    }
    for (let i = 0; i < data.value.length; i++) {
      const d = data.value[i]
      if (d.checked) {
        let checkedV = false
        let checkedA = false

        for (let j = 0; j < d.children.length; j++) {
          const c = d.children[j]
          if (c.checked) {
            if (c.type === 'v') {
              checkedV = true
            } else if (c.type === 'a') {
              checkedA = true
            }
          }

        }
        if (!checkedV) {
          showTooltipAndShake(d, 'v')
          message.error(`请至少选择一条视频轨:${d.name}`)

          return
        }
        if (!checkedA) {
          showTooltipAndShake(d, 'a')
          message.error(`请至少选择一条音频轨:${d.name}`)

          return
        }

      }
    }
    const s = JSON.stringify(data.value);
    loading.value = true

    finishPercent.value = 0
    window.electronAPI.start(mkvtoolnix.value, s, 1)
  }
}
const clearLog = () => {
  mkvmegerProcess.value = ''
}
const clear = (e) => {
  data.value = []
  // lose.value = 0
  expandedKeys.value = []
  checkedKeys.value = []
  indeterminateKeys.value = []
  fixedFiles.value = []
  nfoFiles.value = []
  mediainfoFiles.value = []
  miFinished.value = false

}
const startMediaInfo = () => {
  if (mediainfoFiles.value.length) {
    // clear()
    runMediaInfo(0)
  } else {
    notifyError(`根据查询规则未发现符合文件`);
  }
}
const transSize = size => {
  if (size) {
    const kb = 1024
    const unit = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
    const i = Math.floor(Math.log(size) / Math.log(kb))
    // let unit = size < 1024 ? 'KB' : size < 1024*1024 ? 'MB'
    return (size / Math.pow(kb, i)).toPrecision(3) + ' ' + unit[i];
  } else {
    return size
  }
}
const notification = useNotification();
const notifyError = (title, content) => {
  notification['error']({
    title: title,
    content: content,
    duration: 5000,
    keepAliveOnHover: true
  });
}
const selectFiles = async files => {
  if (files.length) {
    for (let i = 0; i < files.length; i++) {
      const file = files[i]
      if (file.name.endsWith(".fixed")) {
        fixedFiles.value.push(file)
      }
      if (readNfo.value && file.name.endsWith(".nfo")) {
        nfoFiles.value.push(file)
      }
    }

    const duplicates = []
    for (let i = 0; i < files.length; i++) {
      const file = files[i]
      if (fixedFiles.value.some(f => f.path === `${file.path}.fixed`)) {
        file.fixed = true
        if (ignoreFixed.value) {
          continue
        }
      }
      if (file.name.endsWith(".mkv")) {

        if (mediainfoFiles.value.some(f => f.path === file.path)) {
          duplicates.push(file)
          continue
        }
        mediainfoFiles.value.push(file)
      }
    }
    if (duplicates.length) {
      notifyError(`发现重复文件`, `${duplicates.map(d => d.name).join('\n')}`)
    }
    const fixeds = mediainfoFiles.value.filter(f => f.fixed);
    const fixedPromises = []
    for (let i = 0; i < fixeds.length; i++) {
      const getFixed = (file) => {
        return new Promise((resolve, reject) => {
          window.electronAPI.getFixed(file.path).then((fixedContent) => {
            resolve({fixedContent, file})
          })
        })
      }
      fixedPromises.push(getFixed(fixeds[i]))
    }

    const nfoPromises = []
    if (readNfo.value) {
      mediainfoFiles.value.forEach(f => {
        const getNfo = (file) => {
          return new Promise((resolve, reject) => {
            window.electronAPI.getNfo(f.path).then((nfoContent) => {
              resolve({nfoContent, file})
            })
          })
        }
        nfoPromises.push(getNfo(f))
      })
    }

    Promise.all(fixedPromises).then((args) => {
      for (let i = 0; i < args.length; i++) {
        const {fixedContent, file} = args[i]
        if (fixedContent) {
          const fixedJson = JSON.parse(fixedContent)
          if (fixedJson) {
            file.oldSize = fixedJson.oldSize
            file.oldSizeFormat = fixedJson.oldSizeFormat
          }
        }
      }
      if (readNfo.value) {
        Promise.all(nfoPromises).then((args) => {
          for (let i = 0; i < args.length; i++) {
            const {nfoContent, file} = args[i]
            if (nfoContent) {
              const nfo = JSON.parse(nfoContent)
              if (nfo.movie) {
                file.tName = nfo.movie.title
                if (nfo.movie.languages) {
                  file.languages = nfo.movie.languages
                }
              } else {
                file.tName = nfo.episodedetails.showtitle
                if (nfo.episodedetails.languages) {
                  file.languages = nfo.episodedetails.languages
                }
              }
            }
          }
          startMediaInfo()
        })
      } else {
        startMediaInfo()
      }
    })

  }
}

const runMediaInfo = async (index) => {
  current.value = index
  const file = mediainfoFiles.value[index]
  if (data.value.some(d => d.path === file.path)) {
    return
  }
  spinShow.value = true
  // Initialise MediaInfo
  let MI

  const trans = (MM = {g: {}, v: [], a: [], t: []}) => {
    log(`mediainfo库读取成功，开始转换.${file.path}`)
    let cache = true
    if (Object.keys(MM.g).length === 0 && MI) {
      cache = false
      // MI.Option("language_update", translate.value)
      const generalParamCount = MI.Count_Get(MediaInfoModule.Stream.General, 0);
      for (let i = 0; i < generalParamCount; i++) {
        const name = MI.GetI(MediaInfoModule.Stream.General, 0, i, MediaInfoModule.Info.Name);
        if (name) {
          const info = MI.Get(MediaInfoModule.Stream.General, 0, name, MediaInfoModule.Info.Text);
          if (info) {
            MM.g[name] = info
          }
        }
      }
    }
    if (MM.g.hasOwnProperty("$")) {
      cache = false
    }
    const appendText = text => {
      if (text) {
        return ` | ${text}`
      } else {
        return ''
      }
    }
    const renderIcon = icon => {
      return () => <n-icon component={icon}></n-icon>
    }
    const o = {}
    const children = []

    o.key = file.path
    o.name = file.name
    o.path = file.path
    o.expand = true
    const duration = MM.g['Duration/String3']
    const fileSize = MM.g['FileSize/String4']
    const informGeneral = MM.g['Inform']
    const titleGeneral = file.name + appendText(duration) + appendText(fileSize)
    o.label = titleGeneral
    o.size = file.size
    o.sizeFormat = transSize(file.size)
    o.inform = informGeneral
    o.fixed = file.fixed
    o.oldSize = file.oldSize
    o.tName = file.tName
    o.languages = file.languages
    // o.prefix = renderIcon(Document)
    o.suffix = () => <n-tag type="success" size="small" round strong>
      {index + 1}
    </n-tag>


    let videoCount = MM.v.length
    if (videoCount === 0 && MI) {
      videoCount = MI.Count_Get(MediaInfoModule.Stream.Video);
    }
    if (videoCount) {
      for (let i = 0; i < videoCount; i++) {
        if (!MM.v[i] && MI) {
          const vv = {}
          const paramCount = MI.Count_Get(MediaInfoModule.Stream.Video, i);
          for (let j = 0; j < paramCount; j++) {
            const name = MI.GetI(MediaInfoModule.Stream.Video, i, j, MediaInfoModule.Info.Name);
            if (name) {
              const info = MI.Get(MediaInfoModule.Stream.Video, i, name, MediaInfoModule.Info.Text);
              if (info) {
                vv[name] = info
              }
            }
          }
          MM.v.push(vv)
        }
        const title = "视频轨 : " + MM.v[i]['Format/String']
            + appendText(MM.v[i]['Duration/String3'])
            + appendText(MM.v[i]['Width'] + "x" + MM.v[i]['Height'])
            + appendText(MM.v[i]['BitRate/String'])
            + appendText(MM.v[i]['HDR_Format/String'])
            + appendText(MM.v[i]['colour_primaries'])
            + appendText(MM.v[i]['BitDepth/String'])
            + appendText(MM.v[i]['StreamSize/String4'])

        const inform = MM.v[i]['Inform']
        const id = MM.v[i]["ID"]
        children.push({
          key: `${file.path}.${id}`,
          type: "v",
          id: id,
          expand: true,
          fixed: o.fixed,
          // checked: true,
          inform: inform,
          titleGeneral: titleGeneral,
          title: title,
          size: MM.v[i]['StreamSize'],
          language: MM.v[i]['Language/String']
        })
      }
    }

    let hasOtherLanguageAudio = false
    let audioCount = MM.a.length
    if (audioCount === 0 && MI) {
      audioCount = MI.Count_Get(MediaInfoModule.Stream.Audio);
    }
    if (audioCount) {
      for (let i = 0; i < audioCount; i++) {
        if (!MM.a[i] && MI) {
          const aa = {}
          const paramCount = MI.Count_Get(MediaInfoModule.Stream.Audio, i);
          for (let j = 0; j < paramCount; j++) {
            const name = MI.GetI(MediaInfoModule.Stream.Audio, i, j, MediaInfoModule.Info.Name);
            if (name) {
              const info = MI.Get(MediaInfoModule.Stream.Audio, i, name, MediaInfoModule.Info.Text);
              if (info) {
                aa[name] = info
              }
            }
          }
          MM.a.push(aa)
        }
        const title = "音频轨 : " + MM.a[i]['Format/String']
            + appendText(MM.a[i]['Language/String'])
            + appendText(MM.a[i]["Format_Commercial_IfAny"])
            + appendText(MM.a[i]["Channel(s)/String"])
            + appendText(MM.a[i]["Compression_Mode/String"])
            + appendText(MM.a[i]["Title"])
            + appendText(MM.a[i]['StreamSize/String4'])
        const inform = MM.a[i]['Inform']
        const id = MM.a[i]["ID"]
        const language = MM.a[i]['Language/String']
        children.push({
          key: `${file.path}.${id}`,
          type: "a",
          id: id,
          expand: true,
          fixed: o.fixed,
          // checked: true,
          inform: inform,
          titleGeneral: titleGeneral,
          title: title,
          size: MM.a[i]['StreamSize'],
          language: language
        })

        if (i === 0) {
          o.language = language
        } else if (language !== o.language && language !== 'Chinese') {
          hasOtherLanguageAudio = true
        }
      }
      o.hasOtherLanguageAudio = hasOtherLanguageAudio
    }


    let subtitleCount = MM.t.length
    if (!ignoreSubtitle.value) {
      if (subtitleCount === 0 && MI) {
        subtitleCount = MI.Count_Get(MediaInfoModule.Stream.Text);
      }
      if (subtitleCount) {
        for (let i = 0; i < subtitleCount; i++) {
          if (!MM.t[i] && MI) {
            const tt = {}
            const paramCount = MI.Count_Get(MediaInfoModule.Stream.Text, i);
            for (let j = 0; j < paramCount; j++) {
              const name = MI.GetI(MediaInfoModule.Stream.Text, i, j, MediaInfoModule.Info.Name);
              if (name) {
                const info = MI.Get(MediaInfoModule.Stream.Text, i, name, MediaInfoModule.Info.Text);
                if (info) {
                  tt[name] = info
                }
              }
            }
            MM.t.push(tt)
          }
          const title = "字幕轨 : " + MM.t[i]['Format/String']
              + appendText(MM.t[i]['Language/String'])
              + appendText(MM.t[i]['Title'])
          const inform = MM.t[i]['Inform']
          const id = MM.t[i]["ID"]
          children.push({
            key: `${file.path}.${id}`,
            type: "t",
            id: id,
            expand: true,
            fixed: o.fixed,
            // checked: true,
            inform: inform,
            titleGeneral: titleGeneral,
            title: title,
            size: MM.t[i]['StreamSize'],
            language: MM.t[i]['Language/String']
          })
        }
      }
    }
    if (audioCount >= 2) {
      checkedKeys.value.push(o.key)
      expandedKeys.value.push(o.key)
    } else {
      o.singleAudio = true
      if (!noCheckSingleAudio.value) {
        checkedKeys.value.push(o.key)
        expandedKeys.value.push(o.key)
      }
    }
    o.title = `${titleGeneral} (各轨数 : ${videoCount}${appendText(audioCount)}${appendText(subtitleCount)}）`
    o.children = children
    data.value.push(o)
    if (!cache) {
      log(`保存mediainfo到本地缓存.${file.path}`)
      window.electronAPI.saveMediaInfo(file.path, JSON.stringify(MM))
    }
    if (MI) {
      MI.Close();
      //MI.delete();
    }
    const nextIndex = index + 1
    if (mediainfoFiles.value[nextIndex]) {
      runMediaInfo(nextIndex)
    } else {
      spinShow.value = false
      miFinished.value = true
      MI.delete();
      log(`全部文件分析完成，总计${mediainfoFiles.value.length}个`)
    }
  }
  const xmlToJson = (mediainfoXml) => {
    const get = (track) => {
      const o = {}
      for (let k in track) {
        o[k.replaceAll("_", "/")] = track[k][0]
      }
      return o
    }
    const tracks = mediainfoXml.MediaInfo.media[0].track
    let g = {}
    const v = []
    const a = []
    const t = []
    for (let track of tracks) {
      const type = track.$.type
      if (type === "General") {
        g = get(track)
      } else if (type === "Video") {
        v.push(get(track))
      } else if (type === "Audio") {
        a.push(get(track))
      } else if (type === "Text") {
        t.push(get(track))
      }
    }
    return {
      g, v, a, t
    }
  }

  const dealMediainfo = (mediainfo) => {
    if (mediainfo) {
      log(`成功读取到mediainfo本地缓存.${file.path}`)
      // MI = null
      trans(mediainfo)
    } else {
      log(`未读取到mediainfo本地缓存，开始分析.${file.path}`)
      if (!MI) {
        MI = new MediaInfoModule.MediaInfo()
      }
      window.onerror = (msg, url, line) => {
        console.error(msg, url, line)
        log(`全局错误:${msg}`)
        if (msg.indexOf('OOM') !== -1) {
          log(`mediainfo分析文件出错，跳过文件:${file.path}`)
          const nextIndex = index + 1
          if (mediainfoFiles.value[nextIndex]) {
            runMediaInfo(nextIndex)
          } else {
            spinShow.value = false
            miFinished.value = true
            log(`全部文件分析完成，总计${mediainfoFiles.value.length}个`)
          }
        }
      }
      MI.Open(file, () => trans({g: {}, v: [], a: [], t: []}));
    }
  }

  if (readMediainfoXml.value) {
    log(`开始准备读取mediainfo xml.${file.path}`)
    window.electronAPI.getMediaInfoXml(file.path).then(mediainfoXml => {
      if (mediainfoXml) {
        dealMediainfo(xmlToJson(JSON.parse(mediainfoXml)))
      } else {
        log(`开始准备读取mediainfo本地缓存.${file.path}`)
        window.electronAPI.getMediaInfo(file.path).then(mediainfo => {
          dealMediainfo(JSON.parse(mediainfo))
        })
      }
    })
  } else {
    log(`开始准备读取mediainfo本地缓存.${file.path}`)
    window.electronAPI.getMediaInfo(file.path).then(mediainfo => {
      dealMediainfo(JSON.parse(mediainfo))
    })
  }

  //Open the file

}
const initFileUpload = () => {
  const firstChild = upload?.value?.$el?.firstChild
  firstChild?.addEventListener("change", (e) => {
    spinShow.value = false
    selectFiles(e.target.files)
  }, true)
}
let logComponent
const setRefs = el => {
  logComponent = ref(el)
}
const scrollLog = () => {
  nextTick(() => {
    logComponent?.value?.scrollTo({position: "bottom", silent: true});
  });
}
let confJson = reactive({})
const translate = ref('')
const initConf = () => {
  window.electronAPI.getConf().then(conf => {
    if (conf) {
      confJson = reactive(JSON.parse(conf))
      if (confJson.mkvtoolnix) {
        mkvtoolnix.value = confJson.mkvtoolnix
      }
    } else {
      window.electronAPI.system().then(system => {
        if (system === 'win32') {
          mkvtoolnix.value = 'C:\\Program Files\\MKVToolNix'
        } else {
          mkvtoolnix.value = '/Applications/MKVToolNix-85.0.app'
        }
      })
    }
  })


}
const finishPercent = ref(0)
const finishCount = ref(0)
const allCount = ref(0)
const init = () => {
  window.electronAPI.getTranslateConf().then(value => {
    translate.value = value
  })
  initFileUpload()
  initConf()
  window.electronAPI.handleResult((event, value) => {
    log(value)
  })
  window.electronAPI.handleFinish((event, value) => {
    loading.value = false
  })
  window.electronAPI.handleFinishPercent((event, value) => {
    finishPercent.value = value.finishPercent
    finishCount.value = value.finishCount
    allCount.value = value.allCount
    if (value.finishKeys?.length) {
      for (let keyMap of value.finishKeys) {
        const key = keyMap.key
        window.electronAPI.getFixed(key).then((fixedContent) => {
          const d = data.value.find(d => d.key === key)
          const fixedJson = JSON.parse(fixedContent)
          if (fixedJson) {
            d.oldSize = fixedJson.oldSize
            d.oldSizeFormat = fixedJson.oldSizeFormat
          }

          d.fixed = true
          checkedKeys.value.splice(checkedKeys.value.indexOf(key), 1);
          indeterminateKeys.value.splice(indeterminateKeys.value.indexOf(key), 1);
          if (d.children?.length) {
            for (let i = d.children.length - 1; i >= 0; i--) {
              const c = d.children[i]
              if (!checkedKeys.value.includes(c.key)) {
                d.size = keyMap.size
                d.children.splice(i, 1)
              } else {
                c.fixed = true
                checkedKeys.value.splice(checkedKeys.value.indexOf(c.key), 1);
              }
            }

          }
        })

      }
    }
  })


  MediaInfoModule = MediaInfoLib({
    'postRun': () => {
      if (typeof Promise !== 'undefined' && MediaInfoModule instanceof Promise) {
        MediaInfoModule.then(module => {
          MediaInfoModule = module;
        });
      }
    }
  });
  watch(mkvmegerProcess, (newVal) => {
    if (newVal) {
      scrollLog()
    }
  })
}

const checkedAndIndeterminateKeys = computed(() => {
  const a = new Set([...checkedKeys.value, ...indeterminateKeys.value])
  return data.value?.map(i => i.key).filter(i => a.has(i)) || []
})

const selectedKeys = ref([])
const goTo = str => {
  const find = (key) => {
    if (checkedAndIndeterminateKeys.value.includes(key)) {
      tree.value?.scrollTo({key})
      selectedKeys.value = [key]
      setTimeout(() => {
        nextTick(() => {
          shake(key)
        })
      }, 500)

      return true
    }
    return false
  }
  const selectedKey = selectedKeys.value[selectedKeys.value.length - 1]
  for (let i = 0; i < data.value.length; i++) {
    const d = data.value[i]
    if (!selectedKey
        || d.key === selectedKey
        || d.children?.map(c => c.key).includes(selectedKey)) {
      if (str === "up") {
        for (let j = i - 1; j >= 0; j--) {
          if (find(data.value[j].key)) {
            return
          }
        }
      } else {
        for (let j = i + 1; j < data.value.length; j++) {
          if (find(data.value[j].key)) {
            return
          }
        }
      }
    }
  }
}
const up = () => {
  goTo("up")
}
const down = () => {
  goTo("down")
}

onMounted(init)
const log = log => {
  console.log(log)
  mkvmegerProcess.value += log + "\n"
  // scrollLog()
}
const logError = log => {
  mkvmegerProcess.value += log + "\n"
  // scrollLog()
}
const selectMkvtoolnix = (e) => {
  window.electronAPI.mkvtoolnix().then(result => {
    if (result) {
      mkvtoolnix.value = result
    }
  })
}

const show = async () => {
  window.electronAPI.openFile().then(result => {
    mediainfoFiles.value = result
  })

  // for (let resultKey in result) {
  //    this.parseFile(resultKey, this.showResult);
  // }

}
const minimize = () => {
  window.electronAPI.minimize()
}
const maximize = () => {
  window.electronAPI.maximize()
}
const closeApp = () => {
  window.electronAPI.close()
}
</script>
<style>
.demo-spin-icon-load {
  animation: ani-demo-spin 1s linear infinite;
}

.shake {
  animation: shake 0.82s cubic-bezier(0.36, 0.07, 0.19, 0.97) both 3;
  transform: translate3d(0, 0, 0);
}

@keyframes shake {
  10%,
  90% {
    transform: translate3d(-1px, 0, 0);
  }
  20%,
  80% {
    transform: translate3d(2px, 0, 0);
  }
  30%,
  50%,
  70% {
    transform: translate3d(-4px, 0, 0);
  }
  40%,
  60% {
    transform: translate3d(4px, 0, 0);
  }
}
</style>
